package helper.scxml.scxml2.t0.case1_cycle

import helper.base.A2LHM
import helper.base.BaseTypeHelper.ListExpand.toArrayList
import helper.base.LHMHelper.A2LHMExpand.addIfAbsent
import helper.base.LHMHelper.A2LHMExpand.addList
import helper.base.debug.DebugHelper.DebuggerList
import helper.base.debug.DebugHelper.DebuggerList.Companion.makeDebuggerList
import helper.scxml.scxml2.EnvHelper.RunResult
import helper.scxml.scxml2.EnvHelper.T3BaseEnv
import helper.scxml.scxml2.SCXMLTuple
import helper.scxml.scxml2.Scxml2Helper.getSCXMLTuple
import helper.scxml.scxml2.StrategyTripleHelper.IRenEventSelector
import helper.scxml.scxml2.StrategyTripleHelper.Type2StrategyTuple
import helper.scxml.scxml2.t0.case1_cycle.EnvHelper.Expand.toCostList

object EnvHelper {
    object Expand {
        fun ArrayList<RunResult>.toCostList(
        ): ArrayList<Double> {
            return this.map {
                it.endData["c"]!!.toInt().toDouble()
            }.toArrayList()
        }

        fun ArrayList<RunResult>.toMeanCost(
        ): Double {
            return this.toCostList(
            ).average(
            )
        }
    }

    //直接将策略传入环境，这样是不对的
    class Env(
        override val strategyTuple: Type2StrategyTuple,
        private val machineTimeMax: Int,
    ) : T3BaseEnv() {
        override val scxmlTuple = getSCXMLTuple(
            "scxml2/t7_cycle/cycle1.scxml"
        ).also {
            it.initialStateList.add("s0")
            it.renStateList.add("s1")
            it.finalStateList.add("s4")
            arrayListOf("s0", "s1", "s2", "s3").map { stateId ->
                it.stateNeedConsiderClockListLHM.addIfAbsent(
                    stateId,
                    arrayListOf("x"),
                )
            }
            arrayListOf("s0", "s1", "s2", "s3").map { stateId ->
                it.stateDataIncrementLHM.addIfAbsent(
                    stateId,
                    "x",
                    1.0,
                )
            }
            it.stateDataIncrementLHM.run {
                addIfAbsent("s0", "x", 1.0)
                addIfAbsent("s1", "c", 4.0)
                addIfAbsent("s2", "c", 3.0)
                addIfAbsent("s3", "c", 2.0)
            }
        }

        override val ifMachineTimeMax: Boolean
            get() {
                return dataGlobalTimeInt >= machineTimeMax
            }

        fun repeatRun2(
            times: Int,
            runResultList: ArrayList<RunResult> = ArrayList(),
            debuggerList: DebuggerList = makeDebuggerList(),
        ) {
            repeat(times) {
                this.taskRun2(
                    debuggerList = debuggerList
                ).let {
                    debuggerList.pln(
                        it.toStr(0),
                        RunResult.debugger,
                    )
                    runResultList.add(it)
                }
            }
        }

        fun repeatRun2AndRecord(
            times: Int,
            lhm: A2LHM<(SCXMLTuple) -> IRenEventSelector, ArrayList<Double>>? = null,
            runResultList: ArrayList<RunResult> = ArrayList(),
            debuggerList: DebuggerList = makeDebuggerList(),
        ): ArrayList<RunResult> {
            repeatRun2(
                times,
                runResultList,
                debuggerList,
            )
            lhm?.addList(
                this.strategyTuple.getRenEventSelectorFun,
                runResultList.toCostList(),
            )
            return runResultList
        }
    }
}
